﻿using System;
using System.Collections.Generic;
using Internal.Runtime.Services.BattleAttack;
using Runtime.Services.Battle;
using Runtime.Services.Battle.Entity;
using Runtime.Services.BattleSkill;

namespace Runtime.Services.BattleAttack {

    /// <summary>
    /// 战斗攻击快照
    /// </summary>
    public interface IDFR_BattleAttackSnapshot : IDisposable {

        /// <summary>
        /// 攻击ID
        /// </summary>
        DFR_BattleAttackID ID { get; }

        /// <summary>
        /// 来源实例ID
        /// </summary>
        DFR_BattleEntityInstanceID SourceEntityInstanceID { get; }

        /// <summary>
        /// 发动时地图位置
        /// </summary>
        DFR_BattleMapPosition LaunchMapPosition { get; }

        /// <summary>
        /// Debuff实例ID
        /// </summary>
        DFR_BattleEntityInstanceID DebuffEntityInstanceID { get; }

        /// <summary>
        /// 按生命值上限伤害
        /// </summary>
        F64 DamageHPMax { get; }

        /// <summary>
        /// 按当前生命值伤害
        /// </summary>
        F64 DamageHP { get; }

        /// <summary>
        /// 伤害
        /// </summary>
        F64 Damage { get; }

        /// <summary>
        /// 攻击伤害
        /// </summary>
        F64 DamageAttack { get; }

        /// <summary>
        /// 精英额外伤害
        /// </summary>
        F64 DamageAttackBossAdditional { get; }

        /// <summary>
        /// 攻击力
        /// </summary>
        F64 Attack { get; }

        /// <summary>
        /// 精英额外攻击力
        /// </summary>
        F64 AttackBossAdditional { get; }

        /// <summary>
        /// 暴击率
        /// </summary>
        F64 Critical { get; }

        /// <summary>
        /// 暴击伤害强度
        /// </summary>
        F64 CriticalPower { get; }

        /// <summary>
        /// 子弹飞行速度
        /// </summary>
        F64 BulletFlySpeed { get; }

        /// <summary>
        /// 子弹命中资产键
        /// </summary>
        string BulletHitAssetKey { get; }

        /// <summary>
        /// 命中
        /// </summary>
        DFR_BattleAttackHit Hit { get; }

        /// <summary>
        /// 是否是效果
        /// </summary>
        bool IsEffect { get; }

        /// <summary>
        /// 是否禁止对精英产生影响
        /// </summary>
        bool IsForbiddenEliteOrBoss { get; }

        /// <summary>
        /// 影响数量
        /// </summary>
        int InfluenceAmount { get; }

        /// <summary>
        /// 击杀目标集合
        /// </summary>
        IReadOnlyDictionary<DFR_BattleEntityInstanceID, IDFR_BattleAttackTarget> KillTargetDictionary { get; }

        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="skillAttacker">技能进攻者</param>
        /// <param name="originAttacker">原始进攻击</param>
        /// <param name="isEffect">是否是效果</param>
        /// <param name="isForbiddenEliteOrBoss">是否禁止对精英产生影响</param>
        /// <param name="influenceAmount">影响数量</param>
        /// <param name="bulletProvider">子弹提供者</param>
        /// <param name="useOriginAttacker">是否使用原始攻击者的相关数据</param>
        void Initialize(IDFR_BattleAttacker skillAttacker, IDFR_BattleAttacker originAttacker, bool isEffect, bool isForbiddenEliteOrBoss, int influenceAmount, IDFR_BattleAttackBulletProvider bulletProvider, bool useOriginAttacker);

        /// <summary>
        /// 清理引用对象，使当前快照只保留结构体数据
        /// </summary>
        void Lightweight();
    }

    [Implement(typeof(IDFR_BattleAttackSnapshot))]
    internal sealed class DFR_BattleAttackSnapshot : DFR_PoolObject, IDFR_BattleAttackSnapshot {

        public DFR_BattleAttackID ID { get; private set; }

        public DFR_BattleEntityInstanceID SourceEntityInstanceID { get; private set; }

        public DFR_BattleMapPosition LaunchMapPosition { get; private set; }

        public DFR_BattleEntityInstanceID DebuffEntityInstanceID { get; private set; }

        public F64 DamageHPMax { get; private set; }

        public F64 DamageHP { get; private set; }

        public F64 Damage { get; private set; }

        public F64 DamageAttack { get; private set; }

        public F64 DamageAttackBossAdditional { get; private set; }

        public F64 Attack { get; private set; }

        public F64 AttackBossAdditional { get; private set; }

        public F64 Critical { get; private set; }

        public F64 CriticalPower { get; private set; }

        public F64 BulletFlySpeed { get; private set; }

        public string BulletHitAssetKey { get; private set; }

        public DFR_BattleAttackHit Hit { get; private set; }

        public bool IsEffect { get; private set; }

        public bool IsForbiddenEliteOrBoss { get; private set; }

        public int InfluenceAmount { get; private set; }

        public IReadOnlyDictionary<DFR_BattleEntityInstanceID, IDFR_BattleAttackTarget> KillTargetDictionary { get; private set; }

        protected override void Allocate() {
        }

        protected override void Release() {
            Lightweight();
            (BattleAttackService.Instance as IDFR_BattleAttackServiceInternal).ReleaseSnapshot(this);
        }

        public void Lightweight() {
            KillTargetDictionary = null;
        }

        public void Initialize(IDFR_BattleAttacker attacker, IDFR_BattleAttacker originAttacker, bool isEffect, bool isForbiddenEliteOrBoss, int influenceAmount, IDFR_BattleAttackBulletProvider bulletProvider, bool useOriginAttacker) {

            ID = new DFR_BattleAttackID { GUID = Guid.NewGuid() };

            SourceEntityInstanceID = attacker.EntityInstanceID;
            LaunchMapPosition = attacker.MapPosition;

            if (attacker is IDFR_BattleSkillAttacker skill) {
                KillTargetDictionary = skill.KillTargetDictionary;
                if (skill.DebuffEffectModel != null) {
                    DebuffEntityInstanceID = skill.DebuffEffectModel.EntityInstanceID;
                } else {
                    DebuffEntityInstanceID = DFR_BattleEntityInstanceID.Empty;
                }
            } else {
                DebuffEntityInstanceID = DFR_BattleEntityInstanceID.Empty;
                KillTargetDictionary = null;
            }

            Hit = attacker.AttackHit;

            if (originAttacker != null) {
                DamageAttack = originAttacker.Attack.Value;
                DamageAttackBossAdditional = originAttacker.AttackBossAdditional.Value;
            } else {
                DamageAttack = default;
                DamageAttackBossAdditional = default;
            }

            if (useOriginAttacker && originAttacker != null) {
                DamageHPMax = originAttacker.DamageHPMax == null ? default : originAttacker.DamageHPMax.Value;
                DamageHP = originAttacker.DamageHP == null ? default : originAttacker.DamageHP.Value;
                Damage = originAttacker.Damage == null ? default : originAttacker.Damage.Value;
                Attack = originAttacker.Attack == null ? default : originAttacker.Attack.Value;
                AttackBossAdditional = originAttacker.AttackBossAdditional == null ? default : originAttacker.AttackBossAdditional.Value;
                Critical = originAttacker.Critical == null ? default : originAttacker.Critical.Value;
                CriticalPower = originAttacker.CriticalPower == null ? default : originAttacker.CriticalPower.Value;
            } else {
                DamageHPMax = attacker.DamageHPMax == null ? default : attacker.DamageHPMax.Value;
                DamageHP = attacker.DamageHP == null ? default : attacker.DamageHP.Value;
                Damage = attacker.Damage == null ? default : attacker.Damage.Value;
                Attack = attacker.Attack == null ? default : attacker.Attack.Value;
                AttackBossAdditional = attacker.AttackBossAdditional == null ? default : attacker.AttackBossAdditional.Value;
                Critical = attacker.Critical == null ? default : attacker.Critical.Value;
                CriticalPower = attacker.CriticalPower == null ? default : attacker.CriticalPower.Value;
            }

            if (bulletProvider != null) {
                BulletFlySpeed = bulletProvider.BulletFlySpeed * attacker.AttackSpeedFinalFactor;
                BulletHitAssetKey = bulletProvider.BulletHitAssetKey;
            } else {
                BulletFlySpeed = F64.Zero;
                BulletHitAssetKey = null;
            }

            IsEffect = isEffect;
            IsForbiddenEliteOrBoss = isForbiddenEliteOrBoss;
            InfluenceAmount = influenceAmount;
        }
    }
}
